package com.example.stock.controller;

import com.example.stock.controller.dto.GBStaYearLineDto;
import com.example.stock.controller.vo.*;
import com.example.stock.excel.*;
import com.example.stock.model.GBSta;
import com.example.stock.model.MonthDetail;
import com.example.stock.model.WeekDetail;
import com.example.stock.service.*;
import com.example.stock.service.impl.GBStaServiceImpl;
import com.example.stock.util.Result;
import com.example.stock.util.ResultGenerator;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Log4j2
@CrossOrigin(origins = "*")
@RequestMapping("statistic")
@RestController
public class StatisticController {

    @Autowired
    StatisticService statisticService;

    @Autowired
    MonthDataService monthDataService;

    @Autowired
    WeekDataService weekDataService;

    @Autowired
    YearDataService yearDataService;

    @Autowired
    GBStaService gbStaService;

    @Autowired
    StockService stockService;

    private List<String> getSortedKeys(Set<String> keys) {
        return keys.stream()
                .sorted(Comparator.comparing(String::toString).reversed())
                .collect(Collectors.toList());
    }

    /**
     * 获取突破10分位点数据
     * @return
     */
    @GetMapping("monthLpUp")
    public Result getMonthLpUp() {

        BaseVO<MonthLpUp> monthLpUpVO = new BaseVO<>();
        Map<String, List<MonthLpUp>> monthLpUp = statisticService.getMonthLpUp();

        monthLpUpVO.setDates(getSortedKeys(monthLpUp.keySet()));
        monthLpUpVO.setData(monthLpUp);

        return ResultGenerator.genSuccessResult(monthLpUpVO);
    }

    @GetMapping("monthLpNewHigh")
    public Result getMonthLpNewHighDetail(@RequestParam(required = false) String month) {
        LpDetailVO<MonthDetail> vo = new LpDetailVO<>();

        Map<String, List<MonthLpNewHigh>> monthLpNewHigh = statisticService.getMonthLpNewHigh();
        List<String> months = getSortedKeys(monthLpNewHigh.keySet());
        vo.setDates(months);
        vo.setStat(stat(monthLpNewHigh));

        if (month == null) {
            month = months.getFirst();
        }

        List<String> stocks = monthLpNewHigh.get(month).stream()
                .sorted(Comparator.comparing(MonthLpNewHigh::getMonthPct).reversed())
                .map(MonthLpNewHigh::getStock).toList();
        Map<String, List<MonthDetail>> monthRawData = monthDataService.getMonthRawData(stocks);
        vo.setData(buildMonthData(monthRawData, month));

        return ResultGenerator.genSuccessResult(vo);
    }

    private <T> Map<String, Integer> stat(Map<String, List<T>> data) {
        Map<String, Integer> ret = new HashMap<>();
        data.forEach((k, l) -> {
            ret.put(k, l.size());
        });
        return ret;
    }

    @GetMapping("monthLpUpDetail")
    public Result getMonthLpUpDetail(@RequestParam(required = false) String month) {

        LpDetailVO<MonthDetail> monthLpUpDetailVO = new LpDetailVO<>();

        Map<String, List<MonthLpUp>> monthLpUp = statisticService.getMonthLpUp();
        List<String> months = getSortedKeys(monthLpUp.keySet());
        monthLpUpDetailVO.setDates(months);
        if (month == null) {
            month = months.getFirst();
        } else if (!months.contains(month)) {
            return ResultGenerator.genSuccessResult(monthLpUpDetailVO);
        }

        monthLpUpDetailVO.setStat(stat(monthLpUp));

        List<String> stocks = monthLpUp.get(month).stream()
                .sorted(Comparator.comparing(MonthLpUp::getMonthPct).reversed())
                .map(MonthLpUp::getStock).toList();
        Map<String, List<MonthDetail>> monthRawData = monthDataService.getMonthRawData(stocks);
        monthLpUpDetailVO.setData(buildMonthData(monthRawData, month));

        return ResultGenerator.genSuccessResult(monthLpUpDetailVO);
    }

    @GetMapping("monthLpDown")
    public Result getMonthLpDown() {

        BaseVO<MonthLpDown> vo = new BaseVO<>();

        Map<String, List<MonthLpDown>> mothLpDown = statisticService.getMonthLpDown();
        List<String> keys = getSortedKeys(mothLpDown.keySet());

        vo.setDates(keys);
        vo.setData(mothLpDown);

        return ResultGenerator.genSuccessResult(vo);
    }

    @GetMapping("monthLpDownDetail")
    public Result getMonthLpDownDetail(@RequestParam(required = false) String month) {

        LpDetailVO<MonthDetail> monthLpDownDetailVO = new LpDetailVO<>();

        // 获取跌破10分位点记录
        Map<String, List<MonthLpDown>> monthLpDown = statisticService.getMonthLpDown();
        List<String> months = getSortedKeys(monthLpDown.keySet());
        monthLpDownDetailVO.setDates(months);

        if (month == null) {
            month = months.getFirst();
        } else if (!months.contains(month)) {
            return ResultGenerator.genSuccessResult(monthLpDownDetailVO);
        }

        monthLpDownDetailVO.setStat(stat(monthLpDown));

        List<String> stocks = monthLpDown.get(month).stream()
                .sorted(Comparator.comparing(MonthLpDown::getMonthPct))
                .map(MonthLpDown::getStock).toList();

        Map<String, List<MonthDetail>> monthRawData = monthDataService.getMonthRawData(stocks);
        monthLpDownDetailVO.setData(buildMonthData(monthRawData, month));

        return ResultGenerator.genSuccessResult(monthLpDownDetailVO);
    }

    private Map<String, List<MonthDetail>> buildMonthData(Map<String, List<MonthDetail>> monthRawData, String month) {
        Map<String, List<MonthDetail>> ret = new LinkedHashMap<>();

        // 限制返回的记录数
        monthRawData.forEach((k, v) -> {
            // 往前 30 个月，往后 5 个月
            List<MonthDetail> lastItems = v.stream()
                    .sorted(Comparator.comparing(MonthDetail::getDate).reversed())
                    .filter(item -> item.getDate().compareTo(month) <= 0).limit(30)
                    .toList();

            List<MonthDetail> firstItems = v.stream()
                    .sorted(Comparator.comparing(MonthDetail::getDate))
                    .filter(item -> item.getDate().compareTo(month) > 0).limit(12)
                    .toList();

            ret.put(k, Stream.concat(firstItems.stream(), lastItems.stream())
                    .sorted(Comparator.comparing(MonthDetail::getDate).reversed())
                    .collect(Collectors.toList()));
        });

        return ret;
    }

    /**
     * 上穿300日线
     * @return
     */
    @GetMapping("yearLineUp")
    public Result getYearLineUp(@RequestParam(required = false) String date) {

        Map<String, Object> ret = new HashMap<>();

        List<String> weekPctStatKeys = weekDataService.getWeekPctStatKeys();
        ret.put("date",weekPctStatKeys);
        if (date == null) {
            date = weekDataService.getWeekPctStatKeys().getFirst();
        }

        List<GBSta> gb60WStaByDate = gbStaService.getGB60WStaByDate(date).stream()
                .filter(i -> i.getDisPct() >= 0).toList();

        ret.put("data",formatGBStaYearLineDta(gb60WStaByDate));

        return ResultGenerator.genSuccessResult(ret);
    }

    @GetMapping("yearLineDown")
    public Result getYearLineDown(@RequestParam(required = false) String date) {
        Map<String, Object> ret = new HashMap<>();
        List<String> weekPctStatKeys = weekDataService.getWeekPctStatKeys();
        ret.put("date",weekPctStatKeys);
        if (date == null) {
            date = weekDataService.getWeekPctStatKeys().getFirst();
        }

        List<GBSta> gb60WStaByDate = gbStaService.getGB60WStaByDate(date).stream()
                .filter(i -> i.getDisPct() < 0).toList();

        ret.put("data",formatGBStaYearLineDta(gb60WStaByDate));

        return ResultGenerator.genSuccessResult(ret);
    }

    private List<GBStaYearLineDto> formatGBStaYearLineDta(List<GBSta> list) {

        List<GBStaYearLineDto> gbStaYearLineDtos = new ArrayList<>();
        list.forEach(i -> {
            GBStaYearLineDto gbStaYearLineDto = new GBStaYearLineDto();
            BeanUtils.copyProperties(i, gbStaYearLineDto);

            WeekDetail currentWeekDetail = weekDataService.getCurrentWeekDetail(i.getStock());
            gbStaYearLineDto.setCur60wPct(currentWeekDetail.getDisPct());

            StockInfoVO stockInfo = stockService.getStockInfo(i.getStock());
            gbStaYearLineDto.setCategory(stockInfo.getCategory());
            gbStaYearLineDto.setTag(stockInfo.getTag());

            gbStaYearLineDtos.add(gbStaYearLineDto);
        });
        return gbStaYearLineDtos;
    }

    /**
     * 年线数据详情
     * @param week
     * @return
     */
    @GetMapping("yearLineUpDetail")
    public Result getYearLineUpDetail(@RequestParam(required = false) String week) {

        LpDetailVO<WeekDetail>  yearLineUpDetailVO = new LpDetailVO<>();

        List<String> weeks = weekDataService.getWeekPctStatKeys();
        yearLineUpDetailVO.setDates(weeks);
        if (week == null) {
            week = weeks.getFirst();
        } else if (!weeks.contains(week)) {
            return ResultGenerator.genSuccessResult(yearLineUpDetailVO);
        }

        yearLineUpDetailVO.setStat(stat(gbStaService.getGBUpStaMapByDate(GBStaServiceImpl.GB_60W_K)));
        List<String> stocks = gbStaService.getGB60WStaByDate(week).stream().filter(i -> i.getDisPct() >= 0).map(GBSta::getStock).toList();
        yearLineUpDetailVO.setData(buildWeekData(stocks, week));

        return ResultGenerator.genSuccessResult(yearLineUpDetailVO);
    }

    @GetMapping("yearLineDownDetail")
    public Result getYearLineDownDetail(@RequestParam(required = false) String week) {

        LpDetailVO<WeekDetail>  yearLineDownDetailVO = new LpDetailVO<>();

        List<String> weeks = weekDataService.getWeekPctStatKeys();
        yearLineDownDetailVO.setDates(weeks);
        if (week == null) {
            week = weeks.getFirst();
        } else if (!weeks.contains(week)) {
            return ResultGenerator.genSuccessResult(yearLineDownDetailVO);
        }

        yearLineDownDetailVO.setStat(stat(gbStaService.getGBDownStaMapByDate(GBStaServiceImpl.GB_60W_K)));

        List<String> stocks = gbStaService.getGB60WStaByDate(week).stream().filter(i -> i.getDisPct() < 0).map(GBSta::getStock).toList();
        yearLineDownDetailVO.setData(buildWeekData(stocks, week));

        return ResultGenerator.genSuccessResult(yearLineDownDetailVO);
    }

    private Map<String, List<WeekDetail>>  buildWeekData(List<String> stocks, String week) {
        Map<String, List<WeekDetail>> weekRawData = weekDataService.getWeekRawData(stocks);
        Map<String, List<WeekDetail>> ret = new LinkedHashMap<>();

        // 限制返回的记录数
        weekRawData.forEach((k, v) -> {
            // 往前 52 个周，往后 10 个周
            List<WeekDetail> lastItems = v.stream()
                    .sorted(Comparator.comparing(WeekDetail::getDate).reversed())
                    .filter(item -> item.getDate().compareTo(week) <= 0).limit(52)
                    .toList();

            List<WeekDetail> firstItems = v.stream()
                    .sorted(Comparator.comparing(WeekDetail::getDate))
                    .filter(item -> item.getDate().compareTo(week) > 0).limit(12)
                    .toList();

            ret.put(k, Stream.concat(firstItems.stream(), lastItems.stream())
                    .sorted(Comparator.comparing(WeekDetail::getDate).reversed())
                    .collect(Collectors.toList()));
        });

        return ret;
    }

    @GetMapping("weekLpUpDetail")
    public Result getWeekLpUpDetail(@RequestParam(required = false) String week) {

        LpDetailVO<WeekDetail>  yearLineDownDetailVO = new LpDetailVO<>();

        Map<String, List<WeekLpUp>> weekLpUp = statisticService.getWeekLpUp();
        List<String> weeks = weekLpUp.keySet().stream()
                .sorted(Comparator.comparing(String::toString).reversed()).toList();
        yearLineDownDetailVO.setDates(weeks);

        if (week == null) {
            week = weeks.getFirst();
        }

        yearLineDownDetailVO.setStat(stat(weekLpUp));
        List<String> stocks = weekLpUp.get(week).stream().map(WeekLpUp::getStock).toList();
        yearLineDownDetailVO.setData(buildWeekData(stocks, week));
        return ResultGenerator.genSuccessResult(yearLineDownDetailVO);
    }


    @GetMapping("weekLpNewHighDetail")
    public Result getWeekLpNewHighDetail(@RequestParam(required = false) String week) {

        LpDetailVO<WeekDetail> weekLpNewHighDetailVO = new LpDetailVO<>();

        Map<String, List<WeekLpNewHigh>> weekLpNewHigh = statisticService.getWeekLpNewHigh();
        List<String> weeks = getSortedKeys(weekLpNewHigh.keySet());
        weekLpNewHighDetailVO.setDates(weeks);
        if (week == null) {
            week = weeks.getFirst();
        }

        weekLpNewHighDetailVO.setStat(stat(weekLpNewHigh));
        List<String> stocks = weekLpNewHigh.get(week).stream()
                .sorted(Comparator.comparing(WeekLpNewHigh::getWeekPct).reversed())
                .map(WeekLpNewHigh::getStock)
                .toList();
        weekLpNewHighDetailVO.setData(buildWeekData(stocks, week));
        return ResultGenerator.genSuccessResult(weekLpNewHighDetailVO);
    }

    /**
     * 年涨跌统计
     * @return
     */
    @GetMapping("yearPctStat")
    public Result getYearPctStat() {
        return ResultGenerator.genSuccessResult(yearDataService.getYearPctStatList());
    }

    @GetMapping("yearPctStat/{stock}")
    public Result getYearPctStatByStock(@PathVariable String stock) {
        return ResultGenerator.genSuccessResult(yearDataService.getYearPctStatMap().get(stock));
    }
}
